From: Keir Fraser Date: Fri, 11 Apr 2008 14:37:48 +0000 (+0100) Subject: Support tasklets in Xen as a more dynamic alternative to softirqs. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14231^2~19 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=989a44571e0ad793e17e192e7e5247e6fb8760ad;p=xen.git Support tasklets in Xen as a more dynamic alternative to softirqs. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index c3aa6bfb46..d6aa79c246 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -576,6 +576,8 @@ skip_move: end_boot_allocator(); + softirq_init(); + late_setup_arch(&cmdline); scheduler_init(); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 383a868225..9b025b51b1 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -861,6 +861,8 @@ void __init __start_xen(unsigned long mbi_p) early_boot = 0; + softirq_init(); + early_cpu_init(); paging_init(); diff --git a/xen/common/softirq.c b/xen/common/softirq.c index b6c2b18886..c3618eb7ca 100644 --- a/xen/common/softirq.c +++ b/xen/common/softirq.c @@ -52,6 +52,80 @@ void open_softirq(int nr, softirq_handler handler) softirq_handlers[nr] = handler; } +static DEFINE_PER_CPU(struct tasklet *, tasklet_list); + +void tasklet_schedule(struct tasklet *t) +{ + unsigned long flags; + + if ( test_and_set_bool(t->is_scheduled) ) + return; + + local_irq_save(flags); + t->next = this_cpu(tasklet_list); + this_cpu(tasklet_list) = t; + local_irq_restore(flags); + + raise_softirq(TASKLET_SOFTIRQ); +} + +static void tasklet_action(void) +{ + struct tasklet *list, *t; + + local_irq_disable(); + list = this_cpu(tasklet_list); + this_cpu(tasklet_list) = NULL; + local_irq_enable(); + + while ( (t = list) != NULL ) + { + list = list->next; + + BUG_ON(t->is_running); + t->is_running = 1; + smp_wmb(); + + BUG_ON(!t->is_scheduled); + t->is_scheduled = 0; + + smp_mb(); + t->func(t->data); + smp_mb(); + + t->is_running = 0; + } +} + +void tasklet_kill(struct tasklet *t) +{ + /* Prevent tasklet from re-scheduling itself. */ + while ( t->is_scheduled || test_and_set_bool(t->is_scheduled) ) + cpu_relax(); + smp_mb(); + + /* Wait for tasklet to complete. */ + while ( t->is_running ) + cpu_relax(); + smp_mb(); + + /* Clean up and we're done. */ + t->is_scheduled = 0; +} + +void tasklet_init( + struct tasklet *t, void (*func)(unsigned long), unsigned long data) +{ + memset(t, 0, sizeof(*t)); + t->func = func; + t->data = data; +} + +void __init softirq_init(void) +{ + open_softirq(TASKLET_SOFTIRQ, tasklet_action); +} + /* * Local variables: * mode: C diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index 7734b3374d..440bfa6c6c 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -1,24 +1,20 @@ -#ifndef __XEN_SOFTIRQ_H__ +#if !defined(__XEN_SOFTIRQ_H__) && !defined(__ASSEMBLY__) #define __XEN_SOFTIRQ_H__ -/* Common softirqs come first in the following list. */ -#define TIMER_SOFTIRQ 0 -#define SCHEDULE_SOFTIRQ 1 -#define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2 -#define KEYPRESS_SOFTIRQ 3 -#define NMI_SOFTIRQ 4 -#define PAGE_SCRUB_SOFTIRQ 5 -#define TRACE_SOFTIRQ 6 -#define RCU_SOFTIRQ 7 -#define STOPMACHINE_SOFTIRQ 8 - -#define NR_COMMON_SOFTIRQS 9 - -#include - -#define NR_SOFTIRQS (NR_COMMON_SOFTIRQS + NR_ARCH_SOFTIRQS) - -#ifndef __ASSEMBLY__ +/* Low-latency softirqs come first in the following list. */ +enum { + TIMER_SOFTIRQ = 0, + SCHEDULE_SOFTIRQ, + NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ, + KEYPRESS_SOFTIRQ, + NMI_SOFTIRQ, + PAGE_SCRUB_SOFTIRQ, + TRACE_SOFTIRQ, + RCU_SOFTIRQ, + STOPMACHINE_SOFTIRQ, + TASKLET_SOFTIRQ, + NR_COMMON_SOFTIRQS +}; #include #include @@ -26,11 +22,15 @@ #include #include #include +#include + +#define NR_SOFTIRQS (NR_COMMON_SOFTIRQS + NR_ARCH_SOFTIRQS) typedef void (*softirq_handler)(void); asmlinkage void do_softirq(void); -extern void open_softirq(int nr, softirq_handler handler); +void open_softirq(int nr, softirq_handler handler); +void softirq_init(void); static inline void cpumask_raise_softirq(cpumask_t mask, unsigned int nr) { @@ -56,6 +56,25 @@ static inline void raise_softirq(unsigned int nr) set_bit(nr, &softirq_pending(smp_processor_id())); } -#endif /* __ASSEMBLY__ */ +/* + * TASKLETS -- dynamically-allocatable tasks run in softirq context + * on at most one CPU at a time. + */ +struct tasklet +{ + struct tasklet *next; + bool_t is_scheduled; + bool_t is_running; + void (*func)(unsigned long); + unsigned long data; +}; + +#define DECLARE_TASKLET(name, func, data) \ + struct tasklet name = { NULL, 0, 0, func, data } + +void tasklet_schedule(struct tasklet *t); +void tasklet_kill(struct tasklet *t); +void tasklet_init( + struct tasklet *t, void (*func)(unsigned long), unsigned long data); #endif /* __XEN_SOFTIRQ_H__ */